// On Windows we utilize winmm.dll to support multi media devices.
// Please refer to the Windows Multi Media SDK for details.
// Definitions taken from MMsystem.h

using System;
using System.Runtime.InteropServices;


namespace TagTool.Devices.Midi
{
    /// <summary> Definition of midi message callback function </summary>
    public enum MidiMessage
    {
        InputOpen = 0x3C1,
        InputClose = 0x3C2,
        InputData = 0x3C3,
        InputLongData = 0x3C4,
        InputError = 0x3C5,
        InputLongError = 0x3C6,
        InputMoreData = 0x3CC, // pending events
        OutputOpen = 0x3C7,
        OutputClose = 0x3C8,
        OutputDone = 0x3C9,
        OutputPosition = 0x3CA
    }

    /// <summary> Represents midi INPUT device capabilities </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct MidiInputCaps
    {
        public const int MaximumNameLength = 32;
        public ushort ManufacturerId;
        public ushort ProductId;
        public ushort DriverVersion;
        public ushort Padding; /* dummy for padding */
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaximumNameLength)]
        public string ProductName;
        public uint Support; /* Reserverd. Must be zero */
    }

    /// <summary> Represents midi OUTPUT device capabilities </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct MidiOutputCaps
    {
        public const int MaximumNameLength = 32;
        public ushort ManufacturerId;
        public ushort ProductId;
        public uint DriverVersion;
        public ushort Padding; /* dummy for padding */
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaximumNameLength)]
        public string ProductName;
        public ushort Technology;
        public ushort Voices;
        public ushort Notes;
        public ushort ChannelMask;
        public uint Support; /* Reserverd. Must be zero */
    }

    public static class WinMidi
    {
        #region Input

        [DllImport("winmm.dll", EntryPoint = "midiInGetNumDevs", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static uint MidiInGetNumDevs();

        [DllImport("winmm.dll", EntryPoint = "midiInGetDevCaps", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiInGetDevCaps(uint uDeviceId, ref MidiInputCaps lpMidiInCaps, uint cbMidiInCaps);

        [DllImport("winmm.dll", EntryPoint = "midiInOpen", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiInOpen(ref IntPtr lphMidiIn, uint uDeviceId, MidiInProc dwCallback, uint dwCallbackInstance, uint dwFlags);

        [DllImport("winmm.dll", EntryPoint = "midiInStart", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiInStart(IntPtr hMidiIn);

        [DllImport("winmm.dll", EntryPoint = "midiInClose", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiInClose(IntPtr hMidiIn);

        #endregion

        #region Output

        [DllImport("winmm.dll", EntryPoint = "midiOutGetNumDevs", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static uint MidiOutGetNumDevs();

        [DllImport("winmm.dll", EntryPoint = "midiOutGetDevCaps", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiOutGetDevCaps(uint uDeviceId, ref MidiOutputCaps lpMidiOutCaps, uint cbMidiOutCaps);

        [DllImport("winmm.dll", EntryPoint = "midiOutOpen", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiOutOpen(ref IntPtr plhmo, uint uDeviceId, IntPtr dwCallback, uint dwCallbackInstance, uint dwFlags);

        [DllImport("winmm.dll", EntryPoint = "midiOutClose", CharSet = CharSet.Ansi, ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Winapi)]
        public extern static MMResult MidiOutClose(IntPtr hMidiOut);

        #endregion Output
    }
}
